﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Game.Terrain
{
    public class TerrainAccess
    {
        private readonly TerrainBits _Terrain = new TerrainBits();
        private readonly TerrainBits _TerrainRequired = new TerrainBits();
        private readonly TerrainBits _TerrainNot = new TerrainBits();
        private readonly TerrainBits _TerrainKill = new TerrainBits();
        
        public TerrainBits Terrain
        {
            get { return _Terrain; }
        }
        
        public TerrainBits TerrainRequired
        {
            get { return _TerrainRequired; }
        }
        
        public TerrainBits TerrainNot
        {
            get { return _TerrainNot; }
        }
        
        public TerrainBits TerrainKill
        {
            get { return _TerrainKill; }
        }
        
        public ReadOnlyTerrainAccess ToReadOnly()
        {
            return new ReadOnlyTerrainAccess(this);
        }
    }
    
    public class ReadOnlyTerrainAccess
    {
        private readonly ReadOnlyTerrainBits _Terrain;
        private readonly ReadOnlyTerrainBits _TerrainRequired;
        private readonly ReadOnlyTerrainBits _TerrainNot;
        private readonly ReadOnlyTerrainBits _TerrainKill;
        
        public ReadOnlyTerrainAccess(TerrainAccess access)
        {
            _Terrain = new ReadOnlyTerrainBits(access.Terrain);
            _TerrainRequired = new ReadOnlyTerrainBits(access.TerrainRequired);
            _TerrainNot = new ReadOnlyTerrainBits(access.TerrainNot);
            _TerrainKill = new ReadOnlyTerrainBits(access.TerrainKill);
        }
        
        /// <summary>
        /// at least one of these bits must match on of the terrain
        /// </summary>
        public ReadOnlyTerrainBits Terrain
        {
            get { return _Terrain; }
        }
        
        /// <summary>
        /// ALL these bits must be set in the terrain
        /// </summary>
        public ReadOnlyTerrainBits TerrainRequired
        {
            get { return _TerrainRequired; }
        }
        
        /// <summary>
        /// if one of these bits is set, the field will NOT be accessible
        /// </summary>
        public ReadOnlyTerrainBits TerrainNot
        {
            get { return _TerrainNot; }
        }
        
        /// <summary>
        /// if a terrain is not accessible AND one of these bits is matched,
        /// the unit will be destroyed
        /// </summary>
        public ReadOnlyTerrainBits TerrainKill
        {
            get { return _TerrainKill; }
        }
        
        public bool IsAccessible(TerrainType terrain)
        {
            return IsAccessible(terrain.TerrainBits);
        }
        
        public bool IsAccessible(ReadOnlyTerrainBits bits)
        {
            bool success = false;
            
            for(;;)
            {
                int count = Check(_Terrain, bits);
                if (count == 0)
                {
                    break;
                }
                
                count = Check(_TerrainNot, bits);
                if (count > 0)
                {
                    break;
                }
                
                count = Check(_TerrainKill, bits);
                if (count > 0)
                {
                    break;
                }
                
                success = true;
                break;
            }
            
            return success;
        }

        int Check(ReadOnlyTerrainBits test, ReadOnlyTerrainBits bits)
        {
            int count = 0;
            foreach (TerrainBit bit in bits.GetEnumerator())
            {
                if (test.Contains(bit)) 
                {
                    count++;
                }
            }
            return count;
        }
        
    }
}
